/*
 * HSM Proxy Project.
 * Copyright (C) 2013 FedICT.
 * Copyright (C) 2013 Frank Cornelis.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.fedict.hsm.admin.webapp.security;

import java.security.Principal;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;

import javax.faces.application.Application;
import javax.faces.application.ConfigurableNavigationHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import be.fedict.eid.applet.service.Identity;
import be.fedict.eid.applet.service.cdi.BelgianCertificate;
import be.fedict.eid.applet.service.cdi.BelgianCertificate.CERTIFICATE_TYPE;
import be.fedict.hsm.model.security.AdministratorRoles;
import be.fedict.hsm.model.security.SecurityFunction;

@Named("hsmProxyAuthentication")
@SecurityFunction("SF.I&A.2")
public class AuthenticationController {

	private static final Log LOG = LogFactory
			.getLog(AuthenticationController.class);

	@Inject
	private Identity identity;

	@Inject
	@BelgianCertificate(CERTIFICATE_TYPE.AUTH)
	X509Certificate authenticationCertificate;

	public void login(ComponentSystemEvent event) {
		LOG.debug("login");
		FacesContext facesContext = FacesContext.getCurrentInstance();
		if (facesContext.getResponseComplete()) {
			return;
		}
		if (null == this.authenticationCertificate) {
			/*
			 * Caused by a direct navigation to post-login.jsf
			 */
			redirect(facesContext, "/index.xhtml");
			return;
		}
		byte[] encodedCertificate;
		try {
			encodedCertificate = this.authenticationCertificate.getEncoded();
		} catch (CertificateEncodingException e) {
			LOG.error("certificate encoding error: " + e.getMessage(), e);
			return;
		}
		/*
		 * The challenged certificate is the unique user identifier.
		 */
		String username = DigestUtils.sha1Hex(encodedCertificate);
		String password = this.identity.getCardNumber();
		ExternalContext externalContext = facesContext.getExternalContext();
		HttpServletRequest httpServletRequest = (HttpServletRequest) externalContext
				.getRequest();
		try {
			httpServletRequest.login(username, password);
		} catch (ServletException e) {
			LOG.error("login error: " + e.getMessage(), e);
			accessDenied(facesContext);
			return;
		}
		Principal userPrincipal = httpServletRequest.getUserPrincipal();
		if (null == userPrincipal) {
			accessDenied(facesContext);
			return;
		}
		LOG.debug("user principal: " + userPrincipal.getName());
		LOG.debug("admin role: "
				+ httpServletRequest
						.isUserInRole(AdministratorRoles.ADMINISTRATOR));
		if (false == httpServletRequest
				.isUserInRole(AdministratorRoles.ADMINISTRATOR)) {
			accessDenied(facesContext);
			return;
		}
		String targetViewId = SecurityPhaseListener
				.getTargetViewId(externalContext);
		redirect(facesContext, targetViewId);
	}

	public String logout() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		ExternalContext externalContext = facesContext.getExternalContext();
		HttpServletRequest httpServletRequest = (HttpServletRequest) externalContext
				.getRequest();
		try {
			httpServletRequest.logout();
		} catch (ServletException e) {
			LOG.error("logout error: " + e.getMessage(), e);
		}
		return "/index.xhtml";
	}

	public boolean isLoggedIn() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		ExternalContext externalContext = facesContext.getExternalContext();
		HttpServletRequest httpServletRequest = (HttpServletRequest) externalContext
				.getRequest();
		Principal userPrincipal = httpServletRequest.getUserPrincipal();
		return null != userPrincipal;
	}

	public String getName() {
		return this.identity.getFirstName() + " " + this.identity.getName();
	}

	public String getCardNumber() {
		return this.identity.getCardNumber();
	}

	private void accessDenied(FacesContext facesContext) {
		redirect(facesContext, "/access-denied.xhtml");
	}

	private void redirect(FacesContext facesContext, String viewId) {
		Application application = facesContext.getApplication();
		ConfigurableNavigationHandler configurableNavigationHandler = (ConfigurableNavigationHandler) application
				.getNavigationHandler();
		configurableNavigationHandler.performNavigation(viewId
				+ "?faces-redirect=true");
	}
}
